using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using RTMP.SimpleClient.Helpers;

namespace RTMP.SimpleClient.Messages
{
    /// <summary>
    /// 默认的RTMP消息转换器实现
    /// </summary>
    public class DefaultMessageConverter : IMessageConverter
    {
        private static readonly Dictionary<Type, Func<byte[], RTMPMessage?>> _converters = new()
        {
            { typeof(RTMPCommandMessage), ConvertToCommandMessage },
            { typeof(ConnectResponseMessage), ConvertToConnectResponse },
            { typeof(CreateStreamResponseMessage), ConvertToCreateStreamResponse },
            { typeof(PlayStatusMessage), ConvertToPlayStatus },
            { typeof(PublishStatusMessage), ConvertToPublishStatus },
            { typeof(UserControlMessage), ConvertToUserControl },
            { typeof(AudioDataMessage), ConvertToAudioData },
            { typeof(VideoDataMessage), ConvertToVideoData }
        };

        public async Task<object?> ConvertAsync(byte[] rawData, Type targetType, CancellationToken cancellationToken = default)
        {
            await Task.Yield(); // 确保异步执行

            if (_converters.TryGetValue(targetType, out var converter))
            {
                try
                {
                    return converter(rawData);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"消息转换失败 ({targetType.Name}): {ex.Message}");
                    return null;
                }
            }

            // 如果没有找到特定转换器，尝试通用命令消息转换
            if (targetType.IsSubclassOf(typeof(RTMPCommandMessage)))
            {
                return ConvertToCommandMessage(rawData);
            }

            return null;
        }

        public async Task<T?> ConvertAsync<T>(byte[] rawData, CancellationToken cancellationToken = default) where T : class
        {
            var result = await ConvertAsync(rawData, typeof(T), cancellationToken);
            return result as T;
        }

        public bool CanConvert(Type targetType)
        {
            return _converters.ContainsKey(targetType) || targetType.IsSubclassOf(typeof(RTMPCommandMessage));
        }

        #region 私有转换方法

        private static RTMPCommandMessage? ConvertToCommandMessage(byte[] rawData)
        {
            try
            {
                var response = RTMPCommandHelper.ParseCommandResponse(rawData);
                
                return new RTMPCommandMessage
                {
                    CommandName = response.CommandName ?? string.Empty,
                    TransactionId = response.TransactionId,
                    CommandObject = response.CommandObject as Dictionary<string, object>,
                    AdditionalInfo = response.AdditionalInfo,
                    RawData = rawData
                };
            }
            catch
            {
                return null;
            }
        }

        private static ConnectResponseMessage? ConvertToConnectResponse(byte[] rawData)
        {
            var baseMessage = ConvertToCommandMessage(rawData);
            if (baseMessage == null || (baseMessage.CommandName != "_result" && baseMessage.CommandName != "_error"))
            {
                return null;
            }

            return new ConnectResponseMessage
            {
                CommandName = baseMessage.CommandName,
                TransactionId = baseMessage.TransactionId,
                CommandObject = baseMessage.CommandObject,
                AdditionalInfo = baseMessage.AdditionalInfo,
                ConnectionInfo = baseMessage.AdditionalInfo as Dictionary<string, object>,
                RawData = rawData
            };
        }

        private static CreateStreamResponseMessage? ConvertToCreateStreamResponse(byte[] rawData)
        {
            var baseMessage = ConvertToCommandMessage(rawData);
            if (baseMessage == null || baseMessage.CommandName != "_result")
            {
                return null;
            }

            uint streamId = 0;
            if (baseMessage.AdditionalInfo is double streamIdDouble)
            {
                streamId = (uint)streamIdDouble;
            }

            return new CreateStreamResponseMessage
            {
                CommandName = baseMessage.CommandName,
                TransactionId = baseMessage.TransactionId,
                CommandObject = baseMessage.CommandObject,
                AdditionalInfo = baseMessage.AdditionalInfo,
                NewStreamId = streamId,
                RawData = rawData
            };
        }

        private static PlayStatusMessage? ConvertToPlayStatus(byte[] rawData)
        {
            // 简化实现 - 实际应解析onStatus消息
            try
            {
                var response = RTMPCommandHelper.ParseCommandResponse(rawData);
                if (response.CommandName != "onStatus")
                    return null;

                var details = response.AdditionalInfo as Dictionary<string, object>;
                
                return new PlayStatusMessage
                {
                    Code = details?.GetValueOrDefault("code")?.ToString() ?? string.Empty,
                    Level = details?.GetValueOrDefault("level")?.ToString() ?? string.Empty,
                    Description = details?.GetValueOrDefault("description")?.ToString() ?? string.Empty,
                    Details = details,
                    RawData = rawData
                };
            }
            catch
            {
                return null;
            }
        }

        private static PublishStatusMessage? ConvertToPublishStatus(byte[] rawData)
        {
            // 简化实现 - 实际应解析onStatus消息
            try
            {
                var response = RTMPCommandHelper.ParseCommandResponse(rawData);
                if (response.CommandName != "onStatus")
                    return null;

                var details = response.AdditionalInfo as Dictionary<string, object>;
                
                return new PublishStatusMessage
                {
                    Code = details?.GetValueOrDefault("code")?.ToString() ?? string.Empty,
                    Level = details?.GetValueOrDefault("level")?.ToString() ?? string.Empty,
                    Description = details?.GetValueOrDefault("description")?.ToString() ?? string.Empty,
                    StreamName = details?.GetValueOrDefault("streamName")?.ToString() ?? string.Empty,
                    Details = details,
                    RawData = rawData
                };
            }
            catch
            {
                return null;
            }
        }

        private static UserControlMessage? ConvertToUserControl(byte[] rawData)
        {
            // 简化实现 - 需要解析用户控制消息格式
            if (rawData.Length < 6) return null;

            try
            {
                using var ms = new MemoryStream(rawData);
                using var reader = new BinaryReader(ms);

                var eventType = (UserControlEventType)reader.ReadUInt16();
                var eventData = new List<uint>();

                while (reader.BaseStream.Position < reader.BaseStream.Length - 3)
                {
                    eventData.Add(reader.ReadUInt32());
                }

                return new UserControlMessage
                {
                    EventType = eventType,
                    EventData = eventData.ToArray(),
                    RawData = rawData
                };
            }
            catch
            {
                return null;
            }
        }

        private static AudioDataMessage? ConvertToAudioData(byte[] rawData)
        {
            if (rawData.Length < 1) return null;

            return new AudioDataMessage
            {
                AudioFormat = rawData[0],
                AudioData = rawData.Length > 1 ? rawData[1..] : Array.Empty<byte>(),
                RawData = rawData
            };
        }

        private static VideoDataMessage? ConvertToVideoData(byte[] rawData)
        {
            if (rawData.Length < 1) return null;

            var formatByte = rawData[0];
            var frameType = (VideoFrameType)((formatByte >> 4) & 0x0F);
            var videoFormat = (byte)(formatByte & 0x0F);

            return new VideoDataMessage
            {
                FrameType = frameType,
                VideoFormat = videoFormat,
                VideoData = rawData.Length > 1 ? rawData[1..] : Array.Empty<byte>(),
                RawData = rawData
            };
        }

        #endregion
    }
}